/*River Warren
 *October 15, 2011
 *
 *Inventory.h
 *Inventory object to be used by the game Dungeons and Princesses
 */

#ifndef INVENTORY_H_INCLUDED
#define INVENTORY_H_INCLUDED

#include <vector>
#include <map>
#include <iostream>
#include "Base.h"
#include "Key.h"
#include <typeinfo>
#include "EquipmentType.h"
#include "Potion.h"
//#include "Monster.h"
class LockableContainer;
class Monster;
#define DELIMS ",\n"
#define MAX 250

using namespace std;

class Listing //a single listing in the manifest
{
public:
    string objectType;
    int objectID;
    string description;
};

class LockableContainer;

class Inventory
{
    
private:

protected:
    int numOfItems;
    map<int, Base*> items; //this map is the actual inventory
    vector <Listing> manifest; //this is a list of what's in the inventory
    void deleteFromManifest(int); //delete item from manifest that has been pulled out of inventory

    
    
public:
    Inventory();
    virtual void add(Base*); //add something to the inventory
    //get a list of what's in the inventory
    //this list is a const pointer
    vector<Listing>const * hasObjectInInventory(string object);
    vector<Listing>const * hasObjectInInventory(string object, string type);
    vector<Listing>const * getManifest(){return &manifest;}
    int getNumOfItems(){return numOfItems;}

    template <typename T> T* getItem(int); //lookup item of type T and removes from inventory.         Usage: Potion* p = myInventory.getItem<Potion>(objectID);
    template <typename T> T* seeItem(int); //lookup item of type T but does NOT remove from inventory. Usage: Potion* p = myInventory.seeItem<Potion>(objectID);

    void saveInventory(ostream& out);
    void loadInventory(istream& in);
};

template <typename T>
T* Inventory::getItem(int thisID)
{
    map<int, Base*>::iterator it; //the guy who looks through the warehouse for the item
    it = items.find(thisID); //find the item on the shelf
    if(it == items.end())throw string("invalid objectID");
    T* thisItem = static_cast<T*>(it->second); //the packing of the item
    items.erase(it); //take the item off the shelf
    deleteFromManifest(thisID); //remove item from manifest
    return thisItem; //ship the item
}

template <typename T>
T* Inventory::seeItem(int thisID)
{
    map<int, Base*>::iterator it; //the guy who looks through the warehouse for the item
    it = items.find(thisID); //find the item on the shelf
    if(it == items.end())throw string("invalid objectID");
    T* thisItem = static_cast<T*>(it->second); //the packing of the item

    return thisItem; //ship the item
}

#endif /*INVENTORY_H_INCLUDED*/
